import json

from decimal import Decimal
from django import http
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db import transaction
from django.shortcuts import render

# Create your views here.
from django.views import View

# 订单结算界面
from django_redis import get_redis_connection

from apps.goods.models import SKU
from apps.order.models import OrderInfo, OrderGoods
from apps.users.models import Address
from utils.response_code import RETCODE
from utils.views import LoginRequiredJSONMixin

# 提交订单
class OrderView(LoginRequiredMixin,View):
    def get(self,request):
        # 1.必须是登录用户才可以访问
        # 2.获取登录用户信息
        user = request.user
        # 3.根据用户信息进行地址的查询
        addresses = Address.objects.filter(user=user)
        # 4.获取redis中选中的商品id
        redisc_conn = get_redis_connection('carts')    # 连接redis
        sku_id_count=redisc_conn.hgetall('carts_%s'%user.id)  # {'sku_id':count}    redis中购物车的所有商品id和数量

        selected_ids=redisc_conn.smembers('selected_%s'%user.id)          # [1,2,3]     redis中的选中状态的商品id

        selected_carts={}
        for sku_id in selected_ids:
            selected_carts[int(sku_id)]=int(sku_id_count[sku_id])
            # {sku_id:count}  是选中状态的id
        # 5. 对商品进行查询，遍历查询
        ids = selected_carts.keys()
        # 运费
        freight = 10
        # 金额总结
        total_amount = 0
        # 总数量
        total_count = 0
        skus = []
        for id in ids:
            sku = SKU.objects.get(id=id)
            sku.count = selected_carts[id]
            sku.amount=(sku.price*sku.count)
            # 累加金额
            total_amount += sku.amount
            # 累加数量
            total_count += sku.count

            skus.append(sku)

            # 6. 计算总金额,和总的实付款
        payment_amount = total_amount + freight

        context = {
            'skus': skus,
            'addresses': addresses,
            'freight': freight,
            'payment_amount': payment_amount,
            'total_count': total_count,
            'total_amount': total_amount
        }

        return render(request, 'place_order.html', context=context)
        # 6. 统计计算总金额和总的实付款


# 订单结算
class OrderCommitView(LoginRequiredJSONMixin,View):

    def post(self,request):
        # 1.接收数据
        data = json.loads(request.body.decode())
        address_id=data.get('address_id')
        pay_method = data.get('pay_method')
        # 2.验证数据

        if not all([address_id,pay_method]):
            return http.JsonResponse({'code':RETCODE.PARAMERR})
        # 3. 数据入库
        # 3.1先得生成订单的基本信息。
        # OrderInfo.objects.create（）
        # 获取用户信息
        user = request.user
        # 获取地址信息
        address = Address.objects.get(id=address_id)
        # 生成订单id，自己生成一个主键
        from django.utils import timezone
        order_id=timezone.localtime().strftime('%Y%m%d%H%M%S')+'%06d'%user.id
        # 总金额，总数量，运费 == == 0
        total_count = 0
        total_amount = Decimal('0')
        freight = Decimal('10')
        #
        # 支付方式
        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'],OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return http.JsonResponse({'code':RETCODE.PARAMERR})
        #
        # 订单状态
        if pay_method == OrderInfo.PAY_METHODS_ENUM['CASH']:
            # 如果货到付款，订单状态是待发货
            status=OrderInfo.ORDER_STATUS_ENUM['UNSEND']
        else:
            # 如果支付吧付款，订单状态是代付款
            status = OrderInfo.ORDER_STATUS_ENUM['UNPAID']

        # 添加事务
        with transaction.atomic():
            point = transaction.savepoint()
            order = OrderInfo.objects.create(
                order_id=order_id,
                user=user,
                address=address,
                total_count=total_count,
                total_amount=total_amount,
                freight=freight,
                pay_method=pay_method,
                status=status
            )
            # 3.2 再生成订单商品信息
            # OrderGoods.objects.create（）
            # 连接redis获取hash，set，
            redis_conn = get_redis_connection('carts')
            sku_id_counts = redis_conn.hgetall('carts_%s'%user.id)
            selected_ids = redis_conn.smembers('selected_%s'%user.id)
            # 对redis数据进行类型转化，在转换过程中，
            # 重新组织成为一个选中数据的selected_carts = {sku_id: count}
            new_redis_dict={}
            for id in selected_ids:
                new_redis_dict[int(id)]=int(sku_id_counts[id])
            # 获取商品ids，对ids便利查询
            ids = new_redis_dict.keys()
            for id in ids:
            # 查询商品信息
                sku = SKU.objects.get(id=id)
            # 判断库存是否充足
                buy_count = new_redis_dict[sku.id]
                if buy_count > sku.stock:
                    transaction.savepoint_rollback(point)
                    return http.JsonResponse({'code':RETCODE.STOCKERR})
            # 改变商品库存和销量
            #     sku.stock -= buy_count
            #     sku.sales += buy_count
                    # 加入乐观锁解决并发
                old_stock = sku.stock
                new_stock = old_stock - buy_count
                new_sales = sku.sales + buy_count
                rect = SKU.objects.filter(id=sku.id,stock=old_stock).update(stock=new_stock,sales=new_sales)
                # rect成功返回1,不成功返回0
                if rect == 0:
                    return http.JsonResponse({'code':RETCODE.STOCKERR})
                OrderGoods.objects.create(
                    order=order,
                    sku=sku,
                    count=buy_count,
                    price=sku.price
                )
                order.total_amount += (buy_count*sku.price)
                order.total_count += buy_count
            order.save()
            transaction.savepoint_commit(point)
        # 然后遍历时候进行累加总数据和总金额，然后给订单基本信息进行更新。
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'ok','order_id':order_id,'payment_amount':order.total_amount})


        # # 接受数据
        # data = json.loads(request.body.decode())
        # address_id = data.get('address_id')
        # pay_method = data.get('pay_method')
        # # 验证数据
        # if not all([address_id,pay_method]):
        #     return http.JsonResponse({'code':RETCODE.PARAMERR})
        #
        # # 数据入库,先生成订单的基本信息
        # user= request.user
        # # 获取地址信息
        # try:
        #     address = Address.objects.get(id=address_id)
        # except Address.DoesNotExist:
        #     return http.JsonResponse({'code':RETCODE.PARAMERR})
        # # 生成订单id,自己生成主键
        # from django.utils import timezone
        # order_id = timezone.localtime().strftime('%Y%m%d%H%M%S')+ '%06d'%user.id
        # # 总金额,总数量,运费
        # total_count=0
        # total_amount=Decimal('0')
        # freight=Decimal('10')
        # # 支付方式
        # if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'],OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
        #     return http.JsonResponse({'code':RETCODE.PARAMERR})
        # #订单状态
        # if pay_method == OrderInfo.PAY_METHODS_ENUM['CASH']:
        #     status=OrderInfo.ORDER_STATUS_ENUM['UNSEND']
        # else:
        #     status=OrderInfo.ORDER_STATUS_ENUM['UNPAID']
        #
        # # 事务的开启
        # with transaction.atomic():
        #     point = transaction.savepoint()
        #     order=OrderInfo.objects.create(
        #         order_id=order_id,
        #         user=user,
        #         address=address,
        #         total_count=total_count,
        #         total_amount=total_amount,
        #         freight=freight,
        #         pay_method=pay_method,
        #         status=status
        #     )
        #     # 连接redis获取hash,set
        #     redis_conn = get_redis_connection('carts')
        #     sku_id_counts = redis_conn.hgetall('carts_%s'%user.id)
        #     selected_ids = redis_conn.smembers('selected_%s'%user.id)
        #     # 对redis数据进行类型转化，在转换过程中，
        #     # 重新组织成为一个选中数据的selected_carts = {sku_id: count}
        #     selected_carts={}
        #     for id in selected_ids:
        #         selected_carts[int(id)] = int(sku_id_counts[id])
        #     ids = selected_carts.keys()
        #     # 获取商品ids，对ids便利查询
        #     for id in ids:
        #         # 查询商品信息
        #         sku = SKU.objects.get(id=id)
        #         buy_count = selected_carts[sku.id]
        #         # 判断库存是否充足
        #         if buy_count > sku.stock:
        #             transaction.savepoint_rollback(point)
        #             return http.JsonResponse({'code':RETCODE.STOCKERR,'errmsg':'库存不足'})
        #         # 改变商品库存和销量
        #         # sku.stock -= buy_count
        #         # sku.sales += buy_count
        #         # sku.save()
        #
        #         # 在更新数据前,先查询数据
        #         # 查询现在的数据和之前记录的是否一致
        #
        #         # 乐观锁
        #         # 记住原来的数据
        #         old_stock = sku.stock
        #         # 先把更新后的数据计算出来
        #         new_stock = sku.stock - buy_count
        #         new_sales = sku.sales + buy_count
        #         # 判断并修改数据,如果现在数据和之前查询数据一致,那么就成功
        #         rect = SKU.objects.filter(id=sku.id,stock=old_stock).update(stock=new_stock,
        #                                                                     sales=new_sales)
        #         # rect成功返回1,不成功返回0
        #         if rect == 0:
        #             transaction.savepoint_rollback(point)
        #             return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})
        #
        #         OrderGoods.objects.create(
        #             order=order,
        #             sku=sku,
        #             count=buy_count,
        #             price=sku.price
        #         )
        #         # 然后遍历时候进行累加总数据和总金额，然后给订单基本信息进行更新。
        #         order.total_count += buy_count
        #         order.total_amount += (buy_count*sku.price)
        #     order.save()
        #     transaction.savepoint_commit(point)
        #     # 把redis中的选中的id删除
        #     # redis_conn.hdel('carts_%s'%user.id,*selected_ids)
        #     # redis_conn.srem('selected_%s'%user.id,*selected_ids)
        #
        # return http.JsonResponse({'code':RETCODE.OK,'errmsg':'ok','order_id':order_id,'payment_amount':order.total_amount})
        # 第一遍

# 展示订单成功界面


class OrderSuccessView(View):
    def get(self,request):
        order_id=request.GET.get('order_id')
        payment_amount = request.GET.get('payment_amount')
        pay_method = request.GET.get('pay_method')
        context = {
            'order_id': order_id,
            'payment_amount': payment_amount,
            'pay_method': pay_method
        }
        return render(request,'order_success.html',context)